#!/bin/bash
#
# Copyright(c) 2012-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#

# DESCRIPTION Verify if write mode: read only, works as expected and cache only reads and do not cache writes

TESTS_DIR="$(dirname $0)/../"
. $TESTS_DIR/cas_lib
start_test $*

CACHE_DEVICE_SIZE=1G
CORE_DEVICE_SIZE=2G

BLOCK_SIZE=4096
COUNT=100

IOSTAT_BLOCK_SIZE=1024
if [ $POSIXLY_CORRECT ]; then
    IOSTAT_BLOCK_SIZE=512
fi

L_TEST_STATUS=0

# Use CACHE_DEVICE and CORE_DEVICE provided by configuration file and remove partitions from those devices
TARGET_DEVICE_OPTION="$CACHE_DEVICE" remove_partitions
TARGET_DEVICE_OPTION="$CORE_DEVICE" remove_partitions

# Create 1 primary partitions on CACHE_DEVICE
TARGET_DEVICE_OPTION="$CACHE_DEVICE" PARTITION_SIZE_OPTION=$CACHE_DEVICE_SIZE PARTITION_IDS_OPTION="1" make_primary_partitions

# Create 1 primary partitions on CORE_DEVICE
TARGET_DEVICE_OPTION="$CORE_DEVICE" PARTITION_SIZE_OPTION=$CORE_DEVICE_SIZE PARTITION_IDS_OPTION="1" make_primary_partitions

declare -a MODE=("wt" "wa")

echo "------Test read from cache"

for mode in "${MODE[@]}"
do
    echo "------Start CAS Linux in $mode mode"

# This is where the real test starts
    CACHE_ID_OPTION="1" CACHE_DEVICE_OPTION="${CACHE_DEVICE}"-part1 CACHE_MODE_OPTION="$mode"
        CACHE_FORCE_OPTION="yes" start_cache

    CACHE_ID_OPTION="1" CORE_DEVICE_OPTION="${CORE_DEVICE}"-part1 add_core
    sleep 2

# iostat read
    TMP_CACHE_DEVICE=$(echo "$(realpath ${CACHE_DEVICE})" | cut -c6-)
    run_cmd "dd if=/dev/cas1-1 of=$TMP_DIR/file001.bin bs=$BLOCK_SIZE count=$COUNT skip=10000 iflag=direct"
    READ_CACHE_1=$(iostat "${CACHE_DEVICE}" | grep $TMP_CACHE_DEVICE | awk 'NR==1 {print $5}')
    run_cmd "dd if=/dev/cas1-1 of=$TMP_DIR/file001.bin bs=$BLOCK_SIZE count=$COUNT skip=10000 iflag=direct"
    READ_CACHE_2=$(iostat "${CACHE_DEVICE}" | grep $TMP_CACHE_DEVICE | awk 'NR==1 {print $5}')
    READ_CACHE_DELTA=$((($READ_CACHE_2-$READ_CACHE_1)*IOSTAT_BLOCK_SIZE))
    DATA_READ=$(($COUNT*$BLOCK_SIZE))
    if [ $READ_CACHE_DELTA -eq $DATA_READ ] ; then
        echo -n "Blocks read from cache:$READ_CACHE_DELTA == $DATA_READ"; success
    else
        echo -n "Blocks read from cache:$READ_CACHE_DELTA != $DATA_READ"; error
        L_TEST_STATUS=1
    fi

# Clear up after test
    CACHE_ID_OPTION="1" stop_cache
done

echo "------Test write and than read from cache"

for mode in "${MODE[@]}"
do
    echo "------Start CAS Linux in $mode mode"

# This is where the real test starts
    CACHE_ID_OPTION="1" CACHE_DEVICE_OPTION="${CACHE_DEVICE}"-part1 CACHE_MODE_OPTION="$mode"
        CACHE_FORCE_OPTION="yes" start_cache

    CACHE_ID_OPTION="1" CORE_DEVICE_OPTION="${CORE_DEVICE}"-part1 add_core
    sleep 2

# iostat write and write
    TMP_CORE_DEVICE=$(echo "$(realpath ${CORE_DEVICE})" | cut -c6-)
    WRITE_CORE_0=$(iostat "${CORE_DEVICE}" | grep $TMP_CORE_DEVICE | awk 'NR==1 {print $6}')
    WRITE_CACHE_0=$(iostat "${CACHE_DEVICE}" | grep $TMP_CACHE_DEVICE | awk 'NR==1 {print $6}')
    run_cmd "dd if=$TMP_DIR/file001.bin of=/dev/cas1-1 bs=$BLOCK_SIZE count=$COUNT seek=20000 oflag=direct"
    WRITE_CORE_1=$(iostat "${CORE_DEVICE}" | grep $TMP_CORE_DEVICE | awk 'NR==1 {print $6}')
    WRITE_CACHE_1=$(iostat "${CACHE_DEVICE}" | grep $TMP_CACHE_DEVICE | awk 'NR==1 {print $6}')
    READ_CORE_1=$(iostat "${CORE_DEVICE}" | grep $TMP_CORE_DEVICE | awk 'NR==1 {print $5}')
    READ_CACHE_1=$(iostat "${CACHE_DEVICE}" | grep $TMP_CACHE_DEVICE | awk 'NR==1 {print $5}')
    WRITE_CORE_DELTA_1=$((($WRITE_CORE_1-$WRITE_CORE_0)*IOSTAT_BLOCK_SIZE))
    WRITE_CACHE_DELTA_1=$((($WRITE_CACHE_1-$WRITE_CACHE_0)*IOSTAT_BLOCK_SIZE))
    run_cmd "dd if=/dev/cas1-1 of=$TMP_DIR/file001.bin bs=$BLOCK_SIZE count=$COUNT skip=20000 iflag=direct"
    READ_CORE_2=$(iostat "${CORE_DEVICE}" | grep $TMP_CORE_DEVICE | awk 'NR==1 {print $5}')
    READ_CACHE_2=$(iostat "${CACHE_DEVICE}" | grep $TMP_CACHE_DEVICE | awk 'NR==1 {print $5}')
    READ_CORE_DELTA_2=$((($READ_CORE_2-$READ_CORE_1)*IOSTAT_BLOCK_SIZE))
    READ_CACHE_DELTA_2=$((($READ_CACHE_2-$READ_CACHE_1)*IOSTAT_BLOCK_SIZE))
    DATA_WRITE=$(($COUNT*$BLOCK_SIZE))

# Verify writes on both cache and core
    if [ "$mode" == "wa" ] ; then
        if [ $WRITE_CORE_DELTA_1 -eq $DATA_WRITE ]; then
            echo -n "Blocks write to core: $WRITE_CORE_DELTA_1 == $DATA_WRITE"; success
        else
            echo -n "Blocks write to core: $WRITE_CORE_DELTA_1 != $DATA_WRITE"; error
            L_TEST_STATUS=1
        fi
        if [ $WRITE_CACHE_DELTA_1 -eq 0 ]; then
            echo -n "Blocks write to cache: $WRITE_CACHE_DELTA_1 == 0"; success
        else
            echo -n "Blocks write to cache: $WRITE_CACHE_DELTA_1 != 0"; error
            L_TEST_STATUS=1
        fi
    else
        if [ $WRITE_CORE_DELTA_1 -eq $DATA_WRITE ]; then
            echo -n "Blocks write to core: $WRITE_CORE_DELTA_1 == $DATA_WRITE"; success
        else
            echo -n "Blocks write to core: $WRITE_CORE_DELTA_1 != $DATA_WRITE"; error
            L_TEST_STATUS=1
        fi
        if [ $WRITE_CACHE_DELTA_1 -eq $DATA_WRITE ]; then
            echo -n "Blocks write to cache: $WRITE_CACHE_DELTA_1 == $DATA_WRITE"; success
        else
            echo -n "Blocks write to cache: $WRITE_CACHE_DELTA_1 != $DATA_WRITE"; error
            L_TEST_STATUS=1
        fi
    fi

# Verify reads on both cache and core
    if [ "$mode" == "wa" ] ; then
        if [ $READ_CORE_DELTA_2 -eq $DATA_WRITE ]; then
            echo -n "Blocks read from core: $READ_CORE_DELTA_2 == $DATA_WRITE"; success
        else
            echo -n "Blocks read from core: $READ_CORE_DELTA_2 != $DATA_WRITE"; error
            L_TEST_STATUS=1
        fi
        if [ $READ_CACHE_DELTA_2 -eq 0 ]; then
            echo -n "Blocks read from cache: $READ_CACHE_DELTA_2 == 0"; success
        else
            if [ $READ_CACHE_DELTA_2 -eq 4096 ]; then
                echo -n "Blocks read from cache: $READ_CACHE_DELTA_2 == 4096"; success
            else
                echo -n "Blocks read from cache: $READ_CACHE_DELTA_2 != 0"; error
                L_TEST_STATUS=1
            fi
        fi
    else
        if [ $READ_CORE_DELTA_2 -eq 0 ]; then
            echo -n "Blocks read from core: $READ_CORE_DELTA_2 == 0"; success
        else
            echo -n "Blocks read from core: $READ_CORE_DELTA_2 != 0"; error
            L_TEST_STATUS=1
        fi
        if [ $READ_CACHE_DELTA_2 -ge $DATA_WRITE ]; then
            echo -n "Blocks read from cache: $READ_CACHE_DELTA_2 >= $DATA_WRITE"; success
        else
            echo -n "Blocks read from cache: $READ_CACHE_DELTA_2 != $DATA_WRITE"; error
            L_TEST_STATUS=1
        fi
    fi

# Clear up after test
    CACHE_ID_OPTION="1" stop_cache
done

# Always return 0 at the end of the test - if at any point something has failed
# in the API functions, test will end and return a proper result.
# If you need to check other things during the test and end the test earlier, you
# should end the test using "end_test $retval" function
end_test $L_TEST_STATUS
